///*
// * paging.c
// *
// *  Created on: 19/12/2010
// *      Author: wendell
// *
// * P
// * Set if the page is present in memory.
// *
// * R/W
// * If set, that page is writeable. If unset, the page is read-only. This does
// * not apply when code is running in kernel-mode (unless a flag in CR0 is set).
// *
// * U/S
// * If set, this is a user-mode page. Else it is a supervisor (kernel)-mode
// *  page. User-mode code cannot write to or read from kernel-mode pages.
// *
// * Reserved
// * These are used by the CPU internally and cannot be trampled.
// *
// * A
// * Set if the page has been accessed (Gets set by the CPU).
// *
// * D
// * Set if the page has been written to (dirty).
// *
// * AVAIL
// * These 3 bits are unused and available for kernel-use.
// *
// * Page frame address
// * The high 20 bits of the frame address in physical memory.
// *
// * Enabling paging is extremely easy.
// * Copy the location of your page directory into the CR3 register.
// * This must, of course, be the physical address.
// * Set the PG bit in the CR0 register. You can do this by OR-ing with 0x80000000.
// *
// * When a process does something the memory-management unit doesn't like, a
// * page fault interrupt is thrown. Situations that can cause this are
// * (not complete):
// * 		When Reading from or writing to an area of memory that is not mapped
// * 			(page entry/table's 'present' flag is not set
// * 		The process is in user-mode and tries to write to a read-only page.
// * 		The process is in user-mode and tries to access a kernel-only page.
// * 		The page table entry is corrupted - the reserved bits have been overwritten.
// * The page fault interrupt is number 14, and looking at chapter 3 we can see
// * that this throws an error code. This error code gives us quite a bit of
// * information about what happened.
// * Bit 0
// * 		If set, the fault was not because the page wasn't present. If unset, the page wasn't present.
// * Bit 1
// * 		If set, the operation that caused the fault was a write, else it was a read.
// * Bit 2
// * 		If set, the processor was running in user-mode when it was interrupted. Else, it was running in kernel-mode.
// * Bit 3
// * 		If set, the fault was caused by reserved bits being overwritten.
// * Bit 4
// * 		If set, the fault occurred during an instruction fetch.
// * The processor also gives us another piece of information - the address that
// * caused the fault. This is located in the CR2 register. Beware that if your
// * page fault hander itself causes another page fault exception this register
// * will be overwritten - so save it early!
// */
//
//#include <paging.h>
////#include <kheap.h>
//#include <graphic.h>
//#include <string.h>
//#include <system.h>
//#include <memory.h>
//
//// The kernel's page directory
//page_directory_t *kernel_directory=0;
//
//// The current page directory;
//page_directory_t *current_directory=0;
//
//// A bitset of frames - used or free.
//uint *frames;
//uint nframes;
//
//// Defined in kheap.c
//extern uint placement_address;
////extern heap_t *kheap;
//
//// Macros used in the bitset algorithms.
//#define INDEX_FROM_BIT(a) (a/(8*4))
//#define OFFSET_FROM_BIT(a) (a%(8*4))
//
//// A bitset of frames - used or free.
//uint *frames;
//uint nframes;
//
//// Defined in kheap.c
//extern uint placement_address;
//
//// Macros used in the bitset algorithms.
//#define INDEX_FROM_BIT(a) (a/(8*4))
//#define OFFSET_FROM_BIT(a) (a%(8*4))
//
//// Static function to set a bit in the frames bitset
//static void set_frame(uint frame_addr)
//{
//   uint frame = frame_addr/0x1000;
//   uint idx = INDEX_FROM_BIT(frame);
//   uint off = OFFSET_FROM_BIT(frame);
//   frames[idx] |= (0x1 << off);
//}
//
//// Static function to clear a bit in the frames bitset
//static void clear_frame(uint frame_addr)
//{
//   uint frame = frame_addr/0x1000;
//   uint idx = INDEX_FROM_BIT(frame);
//   uint off = OFFSET_FROM_BIT(frame);
//   frames[idx] &= ~(0x1 << off);
//}
//
//// Static function to test if a bit is set.
//static uint test_frame(uint frame_addr)
//{
//   uint frame = frame_addr/0x1000;
//   uint idx = INDEX_FROM_BIT(frame);
//   uint off = OFFSET_FROM_BIT(frame);
//   return (frames[idx] & (0x1 << off));
//}
//
//// Static function to find the first free frame.
//static uint first_frame()
//{
//   uint i, j;
//   for (i = 0; i < INDEX_FROM_BIT(nframes); i++)
//   {
//       if (frames[i] != 0xFFFFFFFF) // nothing free, exit early.
//       {
//           // at least one bit is free here.
//           for (j = 0; j < 32; j++)
//           {
//               uint toTest = 0x1 << j;
//               if ( !(frames[i]&toTest) )
//               {
//                   return i*4*8+j;
//               }
//           }
//       }
//   }
//}
//
//// Function to allocate a frame.
//void alloc_frame(page_t *page, int is_kernel, int is_writeable)
//{
//   if (page->frame != 0)
//   {
//       return; // Frame was already allocated, return straight away.
//   }
//   else
//   {
//       uint idx = first_frame(); // idx is now the index of the first free frame.
//       if (idx == (uint)-1)
//       {
//           // PANIC is just a macro that prints a message to the screen then
//    	   //hits an infinite loop.
//           PANIC("No free frames!");
//       }
//       set_frame(idx*0x1000); // this frame is now ours!
//       page->present = 1; // Mark it as present.
//       page->rw = (is_writeable)?1:0; // Should the page be writeable?
//       page->user = (is_kernel)?0:1; // Should the page be user-mode?
//       page->frame = idx;
//   }
//}
//
//// Function to deallocate a frame.
//void free_frame(page_t *page)
//{
//   uint frame;
//   if (!(frame=page->frame))
//   {
//       return; // The given page didn't actually have an allocated frame!
//   }
//   else
//   {
//       clear_frame(frame); // Frame is now free again.
//       page->frame = 0x0; // Page now doesn't have a frame.
//   }
//}
//
///**
// * Right, let's analyse that. First of all, the utility functions.
// * switch_page_directory does exactly what it says on the tin. It takes a page
// * directory, and switches to it. It does this by moving the address of the
// * tablesPhysical member of that directory into the CR3 register. Remember
// * that the tablesPhysical member is an array of physical addresses. After
// * that it first gets the contents of CR0, then OR-s the PG bit (0x80000000),
// * then rewrites it. This enables paging and flushes the page-directory cache
// * as well.
// *
// * get_page returns a pointer to the page entry for a particular address. It can
// * optionally be passed a parameter - make. If make is 1, and the page table
// * that the requested page entry should reside in hasn't been created, then it
// * will be created. Otherwise, the function would just return 0. So, if the
// * table has already been assigned, it will look up the page entry and return it.
// * If it hasn't (and make == 1), it will attempt to create it.
// *
// * It uses our kmalloc_ap function to retrieve a memory block which is
// * page-aligned, and also gets given it's physical location. The physical
// * location gets stored in 'tablesPhysical' (after several bits have been set
// * telling the CPU that it is present, writeable, and user-accessible), and the
// * virtual location is stored in 'tables'.
// *
// * initialise_paging firstly creates the frames bitset, and sets everything to
// * zero using memset. Then it allocates space (which is page-aligned) for a page
// * directory. After that, it allocates frames such that any page access will map
// * to the frame with the same linear address, called identity-mapping. This is
// * done for a small section of the address space, so the kernel code can continue
// * to run as normal. It registers an interrupt handler for page faults (below)
// * then enables paging.
// */
//// ============= PAGING CODE ================
//void initialise_paging()
//{
//   // The size of physical memory. For the moment we
//   // assume it is 16MB big.
//   uint mem_end_page = 0x1000000;
//
//   nframes = mem_end_page / 0x1000;
//   frames = (uint*)kmalloc(INDEX_FROM_BIT(nframes));
//   memset(frames, 0, INDEX_FROM_BIT(nframes));
//
//   // Let's make a page directory.
//   kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t));
//   memset(kernel_directory, 0, sizeof(page_directory_t));
//   current_directory = kernel_directory;
//
//   // We need to identity map (phys addr = virt addr) from
//   // 0x0 to the end of used memory, so we can access this
//   // transparently, as if paging wasn't enabled.
//   // NOTE that we use a while loop here deliberately.
//   // inside the loop body we actually change placement_address
//   // by calling kmalloc(). A while loop causes this to be
//   // computed on-the-fly rather than once at the start.
//   int i = 0;
//   while (i < placement_address)
//   {
//       // Kernel code is readable but not writeable from userspace.
//       alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
//       i += 0x1000;
//   }
//   // Before we enable paging, we must register our page fault handler.
//   irqInstallHandler(14, page_fault);
//
//   // Now, enable paging!
//   switch_page_directory(kernel_directory);
//}
//
//void switch_page_directory(page_directory_t *dir)
//{
//   current_directory = dir;
//   asm volatile("mov %0, %%cr3":: "r"(&dir->tablesPhysical));
//   uint cr0;
//   asm volatile("mov %%cr0, %0": "=r"(cr0));
//   cr0 |= 0x80000000; // Enable paging!
//   asm volatile("mov %0, %%cr0":: "r"(cr0));
//}
//
//page_t *get_page(uint address, int make, page_directory_t *dir)
//{
//   // Turn the address into an index.
//   address /= 0x1000;
//   // Find the page table containing this address.
//   uint table_idx = address / 1024;
//   if (dir->tables[table_idx]) // If this table is already assigned
//   {
//       return &dir->tables[table_idx]->pages[address%1024];
//   }
//   else if(make)
//   {
//       uint tmp;
//       dir->tables[table_idx] = (page_table_t*)kmalloc_ap(sizeof(page_table_t), &tmp);
//       memset(dir->tables[table_idx], 0, 0x1000);
//       dir->tablesPhysical[table_idx] = tmp | 0x7; // PRESENT, RW, US.
//       return &dir->tables[table_idx]->pages[address%1024];
//   }
//   else
//   {
//       return 0;
//   }
//}
//
//void page_fault(registers_t *regs)
//{
//    // A page fault has occurred.
//    // The faulting address is stored in the CR2 register.
//    uint faulting_address;
//    asm volatile("mov %%cr2, %0" : "=r" (faulting_address));
//
//    // The error code gives us details of what happened.
//    int present   = !(regs->err_code & 0x1); // Page not present
//    int rw = regs->err_code & 0x2;           // Write operation?
//    int us = regs->err_code & 0x4;           // Processor was in user-mode?
//    int reserved = regs->err_code & 0x8;     // Overwritten CPU-reserved bits of page entry?
//    uint id = regs->err_code & 0x10;          // Caused by an instruction fetch?
//
//    // Output an error message.
//    print("Page fault! ( ");
//    if (present) {print("present ");}
//    if (rw) {print("read-only ");}
//    if (us) {print("user-mode ");}
//    if (reserved) {print("reserved ");}
//    print(") at 0x");
//    char hex[10] = " ";
//    itoa(faulting_address, hex);
//    print(hex);
//    print(" - EIP: ");
//    itoa(regs->eip, hex);
//    print(hex);
//    print("\n");
//    PANIC("Page fault");
//}
//

